package org.share.supports.netty.rpc;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.share.develop.common.factoy.NamedThreadFactory;
import org.learn.develop.logger.Logger;
import org.learn.develop.logger.LoggerFactory;
import org.share.supports.netty.NettyConfig;
import org.share.supports.netty.events.BootstrapHook;
import org.share.supports.netty.rpc.support.AbstractRpcRemoting;

import java.net.InetSocketAddress;


public  abstract  class AbstractRpcRemotingServer extends AbstractRpcRemoting implements BootstrapHook,RemotingService {

    Logger logger = LoggerFactory.getLogger(AbstractRpcRemotingServer.class);

    private final ServerBootstrap serverBootstrap;
    private final EventLoopGroup eventLoopGroupWorker;
    private final EventLoopGroup eventLoopGroupBoss;
    private final NettyConfig nettyServerConfig;
    private int listenPort;




    public AbstractRpcRemotingServer(){
        this.serverBootstrap = new ServerBootstrap();
        this.nettyServerConfig = new NettyConfig();

        this.eventLoopGroupBoss = new NioEventLoopGroup(nettyServerConfig.getBossThreadSize(),
                new NamedThreadFactory(nettyServerConfig.getBossThreadPrefix(), nettyServerConfig.getBossThreadSize()));

        this.eventLoopGroupWorker = new NioEventLoopGroup(nettyServerConfig.getWorkThreadSize(),
                new NamedThreadFactory(nettyServerConfig.getWorkThreadPrefix(),nettyServerConfig.getWorkThreadSize()));


        this.listenPort = nettyServerConfig.getListenPort();
    }

    public void start() {
        logger.info("staring at port:\t"+this.listenPort);
        staring();
        this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupWorker)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, nettyServerConfig.getSoBackLogSize())
                .option(ChannelOption.SO_REUSEADDR, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSendBufSize())
                .childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketResvBufSize())
                .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK,
                        new WriteBufferWaterMark(nettyServerConfig.getWriteBufferLowWaterMark(),
                                nettyServerConfig.getWriteBufferHighWaterMark()))
                .localAddress(new InetSocketAddress(listenPort))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) {
                        socketChannelProcess(ch);
                    }
                });


        try {
            ChannelFuture future = this.serverBootstrap.bind(listenPort).sync();
            started();
            future.channel().closeFuture().sync();
        } catch (Exception exx) {
            throw new RuntimeException(exx);
        }

    }

    public void shutdown() { }







}
